'''
Created on Dec 22, 2010

@author: Nican
'''

import wx

class ValueSlider(wx.BoxSizer):
    '''
    classdocs
    '''
    ValueSaver = None

    def __init__(self, parent, id, name, saveName):
        '''
        Constructor
        '''
        wx.BoxSizer.__init__(self, wx.VERTICAL)
        
        self.valueText = wx.StaticText(parent, -1, "0", style=wx.ALIGN_RIGHT)
        self.Slider = wx.Slider(parent, -1, 127, 0, 255)
        self.saveName = saveName
        
        splitter = wx.BoxSizer(wx.HORIZONTAL)
        splitter.Add(wx.StaticText(parent, -1, name + " "), 0, wx.EXPAND)
        splitter.Add(self.valueText, 0, wx.EXPAND)
        
        self.Add(splitter, 0, wx.EXPAND)
        self.Add(self.Slider, 0, wx.EXPAND)
        
        parent.Bind(wx.EVT_SCROLL, self.valueChanged, self.Slider)
        
        self.valueChanged(None)
        
        self.ValueSaver = None
        
    def setValueSaver(self, saver):
        self.ValueSaver = saver

        self.SetValue( int( saver.GetValue( self.saveName, 127 ) ) )
        
    def valueChanged(self, slider):
        value = str(self.Slider.GetValue())
        
        self.valueText.SetLabel(value)
        #wx.Slider.__init__(self, parent, -1, 0, 0, 255)
        
        if self.ValueSaver is not None:
            self.ValueSaver.SetValue( self.saveName, value )
        
    def GetValue(self):
        return self.Slider.GetValue()
    
    def SetValue(self, value):
        self.Slider.SetValue(value)
        self.valueChanged(None)
        
        
class JoystickAxis(wx.Panel):
    
    def __init__(self, parent):
        sty = wx.NO_BORDER
        wx.Panel.__init__(self, parent, style=sty, size=wx.Size(100, 100))
        self.SetBackgroundColour(wx.WHITE)
        
        self.BufferBmp = None
        
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        
        self.Refresh()
        
    def OnSize(self, event):        
        if self.recalculateBuffer():
            self.Refresh()
            
    def recalculateBuffer(self):
        # Get the size of the drawing area in pixels.
        self.wi, self.he = self.GetSizeTuple()
        # Create BufferBmp and set the same size as the drawing area.
        self.BufferBmp = wx.EmptyBitmap(self.wi, self.he)
        memdc = wx.MemoryDC()
        memdc.SelectObject(self.BufferBmp)
        # Drawing job
        ret = self.DoSomeDrawing(memdc)
        if not ret:  #error
            self.BufferBmp = None
            
        return ret

    # OnPaint is executed at the app start, when resizing or when
    # the application windows becomes active. OnPaint copies the
    # buffered picture, instead of preparing (again) the drawing job.
    # This is the trick, copying is very fast.
    # Note: if you forget to define the dc in this procedure,
    # (no dc = ... code line), the application will run in
    # an infinite loop. This is a common beginner's error. (I think)
    # BeginDrawing() and EndDrawing() are for windows platforms (see doc).
    def OnPaint(self, event):
        dc = wx.PaintDC(self)
        
        dc.BeginDrawing()
        if self.BufferBmp != None:
            dc.DrawBitmap(self.BufferBmp, 0, 0, True)
        dc.EndDrawing()
        
        
    
    
    # The function defines the drawing job. Everything is drawn on the dc.
    # In that application, the dc corresponds to the BufferBmp.
    # Three things are drawn, a square with a fixed size, and two
    # rectangles with sizes determined by the size of the dc, that
    # means the size of the drawing area. Keep in mind, the size
    # of the drawing area depends on the size of the main frame,
    # which can be resized on the fly with your mouse.
    # At this point, I will introduce a small complication, that is
    # in fact quite practical. It may happen, the drawing is not
    # working correctly. Either there is an error in the drawing job
    # or the data you want to plot can not be drawn correctly. A typical
    # example is the plotting of 'scientific data'. The data are not (or
    # may not be) scaled correctly, that leads to errors, generally integer
    # overflow errors.
    # To circumvent this, the procedure returns True, if the drawing succeed.
    # It returns False, if the drawing fails. The returned value may be used
    # later.
    def DoSomeDrawing(self, dc):
        try:

            dc.BeginDrawing()
            
            dcwi, dche = dc.GetSizeTuple()

            #~ raise OverflowError #for test
            """
            # Clear everything
            dc.SetBrush(wx.Brush(wx.WHITE, wx.SOLID))
            dc.Clear()

            # Draw the square with a fixed size.
            dc.SetBrush(wx.Brush(wx.CYAN, wx.SOLID))
            dc.SetPen(wx.Pen(wx.BLUE, 1, wx.SOLID))
            dc.DrawRectangle(10, 10, 200, 200)

            # Draw a transparent rectangle with a red border, proportional to
            # the dc size.
            dcwi, dche = dc.GetSizeTuple()
            dc.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
            dc.SetPen(wx.Pen(wx.RED, 1, wx.SOLID))
            dc.DrawRectangle(0, 0, dcwi, dche)

            # Draw one another rectangle, a rectangle with a size proportional
            # to the dc size.
            gap = 50
            dc.SetBrush(wx.Brush(wx.WHITE, wx.TRANSPARENT))
            dc.SetPen(wx.Pen(wx.BLACK, 1, wx.SOLID))
            dc.DrawRectangle(0 + gap, 0 + gap, dcwi - 2 * gap, dche - 2 * gap)

            # These next 2 lines will raise an overflow error.
            #~ largeval = 1e10
            #~ dc.DrawLine(dcwi // 2, dche // 2, largeval, largeval)
            """
            dc.SetBrush(wx.Brush(wx.WHITE, wx.SOLID))
            dc.Clear()
            
            dc.DrawEllipticArc(0, 0, dcwi, dche, 0, 360)

            dc.EndDrawing()
            return True

        except:
            return False     
        
